package com.lin.benchmade.pinyin;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 拼音切分器，分割用户输入的拼音，分割后匹配出对应的汉字
 * 
 * @author xiaolin
 */
@Deprecated
public class Word2PinyinSpliter {
	private final static Logger LOG = LoggerFactory.getLogger(Word2PinyinSpliter.class);
	private static PinyinTrie pinyin_dic = new PinyinTrie();
	private static final String PATH_DIC = "/com/lin/benchmade/pinyin/PinYin.dic";

	static {
		try {
			InputStream is = Word2PinyinSpliter.class.getResourceAsStream(PATH_DIC);
			InputStreamReader isr = new InputStreamReader(is);
			BufferedReader br = new BufferedReader(isr);
			String line;
			while ((line = br.readLine()) != null) {
				pinyin_dic.put(line.toCharArray());
			}
			br.close();
			isr.close();
			is.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 拼音切分器。用正向最大匹配法匹配出完整的拼音
	 * @param pinyin	待拆分的拼音
	 * @return
	 */
	public static List<PinYinBean> inOrderMaxMatch(String pinyin, boolean mix) {
		List<PinYinBean> result = pinyin_dic.inOrderMaxMatch(pinyin, mix);
		return result;
	}

	/**
	 * 最小力度切分拼音
	 * @param pinyin
	 * @return
	 */
	public static List<List<PinYinBean>> minGranularMatch(String pinyin ,boolean isMix) {
		List<List<PinYinBean>> result = pinyin_dic.minGranularMatch(pinyin);
		List<List<PinYinBean>> newResult = null; 
		for (List<PinYinBean> r : result) {
			if(r.get(r.size()-1).isComplete()){
				if(newResult == null){
					newResult = new ArrayList<List<PinYinBean>>();
				}
				newResult.add(r);
			}
		}
		if(newResult!=null){
			result = newResult;
		}
		return result;
	}

	public static void main(String[] args) {
		List<List<PinYinBean>> result = Word2PinyinSpliter.minGranularMatch("jianguomen",true);
		for (List<PinYinBean> r : result) {
			for (int i=0;i<r.size()-1;i++) {
				System.out.print(new String(r.get(i).getPinyin()) + " ");
			}
			System.out.println();
		}
		
	}
}

class PinyinTrie {

	private Map<Character, PinyinTrie> child;
	private boolean isPinyin;
	// 测试用实际可去除这个c
	private Character c;

	public Character getC() {
		return c;
	}

	public void setC(Character c) {
		this.c = c;
	}

	public Map<Character, PinyinTrie> getChild() {
		if (child == null) {
			child = new HashMap<Character, PinyinTrie>();
		}
		return child;
	}

	public void setChild(Map<Character, PinyinTrie> child) {
		this.child = child;
	}

	public boolean isPinyin() {
		return isPinyin;
	}

	public void setPinyin(boolean isPinyin) {
		this.isPinyin = isPinyin;
	}

	public void put(char[] charArray) {
		this.put(charArray, 0, charArray.length);
	}

	public void put(char[] charArray, int begin, int length) {
		Character c = charArray[begin];
		PinyinTrie tpy = getNextNode(c);
		if (length > 1) {
			tpy.put(charArray, begin + 1, length - 1);
		} else if (length == 1) {
			tpy.isPinyin = true;
		}
	}

	private PinyinTrie getNextNode(Character c) {
		PinyinTrie td = this.getChild().get(c);
		if (td == null) {
			td = new PinyinTrie();
			this.getChild().put(c, td);
			td.setC(c);
		}
		return td;
	}

	/**
	 * @param keyWord
	 * @return
	 */
	public List<PinYinBean> inOrderMaxMatch(String keyWord, boolean mix) {
		char[] charArray = keyWord.toCharArray();
		List<PinYinBean> list = new ArrayList<PinYinBean>();
		int offset = 0;
		char[] pyValue;// pinyinbean的拼音值
		boolean pinyin_bool;
		int length;// 每次整个字符串跳过的长度。也就是步长
		while (offset < charArray.length) {
			length = inOrderMaxMatch(charArray, offset, 0) + 1;// 返回的都是少1的长度，所以补一个长度
			switch (length) {
			case 1:// 1说明没有匹配上，所以length=1，是不正确的，因为没有赋值过，所以要手工赋值一下。为了switch后面的统一匹配
				if (!mix) { //add by xiaolin 2012-10-28 if mix is false , return a empty list
					list.clear();
					return list;
				}
				pinyin_bool = false;
				break;
			case 0:
				length = charArray.length - offset;// 0说明是最后一个匹配的，length也是赋值过一次-1，也没有意义，所以也要调整一下。
				pinyin_bool = false;
				break;
			default:
				length = length - offset;
				pinyin_bool = true;
				break;
			}
			pyValue = new char[length];
			System.arraycopy(charArray, offset, pyValue, 0, length);
			offset += length;
			list.add(new PinYinBean(pyValue, pinyin_bool));
		}
		return list;
	}

	public List<List<PinYinBean>> minGranularMatch(String keyWord) {
		List<List<PinYinBean>> result = new ArrayList<List<PinYinBean>>();

		char[] charArray = keyWord.toCharArray();
		int start = 0;
		DoubleArrayMap dam = new DoubleArrayMap();
		while (start < charArray.length) {
			ArrayList<Integer> list = new ArrayList<Integer>(5);
			minGranularMatch(charArray, start, list);
			if (list.size() == 0) {
				dam.put(start, 0);
				start += 1;
			} else {
				for (int i : list) {
					dam.put(start, i);
				}
				start = start == 0 ? list.get(0) : start + 1;
			}
		}
		joinCompose(0, new ArrayList<PinYinBean>(), result, dam, charArray, true);
		return result;
	}
	
	//limit 整个keyword的长度
	public void joinCompose(int num, List<PinYinBean> list, List<List<PinYinBean>> result, DoubleArrayMap dam, char[] charArray, boolean lastState) {
		if (num < charArray.length) {
			byte[] startNode = dam.get(num);
			int av;
			boolean isComplete;
			for (int cursor = 1 ; cursor<startNode[0]; cursor++) {
				isComplete = startNode[cursor]>0;
				//if(isComplete){ //加上这个条件 即只有全拼的才能返回
					ArrayList<PinYinBean> child = new ArrayList<PinYinBean>();
					child.addAll(list);
					av = isComplete ? startNode[cursor] : num + 1;
					char[] pyValue = new char[av-num];
					System.arraycopy(charArray, num, pyValue, 0, av-num);
					child.add(new PinYinBean(pyValue, isComplete));
					if (!(!isComplete && charArray[av - 1] == 'u')) {
						boolean i = lastState ? isComplete : false;
						joinCompose(av, child, result, dam, charArray,i);
					}
				//}
			}
		} else {
			list.add(new PinYinBean(null, lastState));
			result.add(list);
		}
	}

	public void minGranularMatch(char[] value, int start, List<Integer> posList) {
		PinyinTrie tpy = this.getChild().get(value[start]);
		if (tpy != null) {
			if (value.length - start > 1) {
				if (tpy.isPinyin) {// 如果走到一颗树的节点，赋值给pos，因为最大匹配，所以还要往下走，用pos记录下当前位置，如果以后没有匹配上，则取这个位置
					posList.add(start + 1);
				}
				tpy.minGranularMatch(value, start + 1, posList);
			} else {
				posList.add(value.length);// 如果走到树的尽头，char数组也走到尽头，但是还没匹配上，那么说明这个是一个合法的前缀，位置设置为最后一个，用-1做一个特殊标示
			}
		}
	}

	/**
	 * @param value
	 *            固定的关键字的char数组
	 * @param start
	 *            整个字符串的起始位置。
	 * @param pos
	 *            标示进度的位置，如果匹配上，那么这个值等于start的位置。如果没有匹配上，每次传递的值是0，那么不会被赋值，
	 *            所以返回的还是0.如果是0，认为没有匹配上。
	 * @return 返回匹配最大匹配的位置，如果没有匹配，返回0
	 */
	public int inOrderMaxMatch(char[] value, int start, int pos) {
		PinyinTrie tpy = this.getChild().get(value[start]);
		if (tpy != null) {
			if (tpy.isPinyin) {// 如果走到一颗树的节点，赋值给pos，因为最大匹配，所以还要往下走，用pos记录下当前位置，如果以后没有匹配上，则取这个位置
				pos = start;//注意:在这赋值后,在数走到尽头时,还会赋值(pos=-1).
			}
			if (value.length - start > 1) {
				pos = tpy.inOrderMaxMatch(value, start + 1, pos);
			} else {
				pos = -1;// 如果走到树的尽头，char数组也走到尽头，但是还没匹配上，那么说明这个是一个合法的前缀，位置设置为最后一个，用-1做一个特殊标示
			}
		}
		return pos;
	}

}
